<template>
  <QueryBar v-if="$slots.queryForm" mb-30 @search="handleSearch" @reset="handleReset">
    <slot name="queryForm" />
  </QueryBar>

  <n-data-table
    v-bind="$attrs"
    :loading="loading"
    :scroll-x="props.scrollX"
    :data="tableData"
    :row-key="(row: TRecord<any>) => row[props.rowKey]"
  />

  <div v-if="props.isPagination" w-full flex items-center justify-between flex-wrap>
    <span m-t-16>共 {{ pagination.itemCount }} 项</span>
    <n-pagination
      v-model:page="pagination.pageNum"
      m-t-16
      :page-count="pagination.pageCount"
      @update:page="onPageChange"
    />
    <span />
  </div>
</template>

<script setup lang="ts">
import type { Pagination, CrudTable } from './types'
import type { Method } from 'alova'

const props = withDefaults(
  defineProps<{
    columnEdit?: boolean
    refresh?: boolean
    isPagination?: boolean
    scrollX?: number
    rowKey?: string
    queryItems?: Record<string, any>
    extraParams?: TRecord<any>
    getData: (_?: TRecord<any>) => Method | Promise<any>
    handleData?: <T>(_: T[]) => T[]
  }>(),
  {
    columnEdit: true,
    refresh: true,
    isPagination: true,
    scrollX: 0,
    rowKey: 'id',
    queryItems: () => ({}),
    extraParams: () => ({})
  }
)

const emit = defineEmits(['update:queryItems', 'onDataChange'])

const loading = ref(false)
const initQuery = { ...props.queryItems }
const tableData = ref<TRecord<any>[]>([])
const pagination = reactive<Pagination>({ pageNum: 1, pageSize: 10, itemCount: 0, pageCount: 0 })

async function handleQuery() {
  try {
    loading.value = true
    // 如果非分页模式或者使用前端分页,则无需传分页参数
    if (props.isPagination) {
      const { data } = (await props.getData({
        pageNum: pagination.pageNum,
        pageSize: pagination.pageSize,
        condition: {
          ...props.queryItems,
          ...props.extraParams
        }
      })) as ResponseBody<PaginationData<TRecord<any>>>
      tableData.value = props.handleData ? props.handleData(data?.list) : data?.list
      pagination.itemCount = data?.total || 0
      pagination.pageCount = data?.pages || 0
      return Promise.resolve(data)
    } else {
      const { data } = (await props.getData({
        ...props.queryItems,
        ...props.extraParams
      })) as ResponseBody<TRecord<any>[]>
      tableData.value = props.handleData ? props.handleData(data) : data
      return Promise.resolve(data)
    }
  } catch (error) {
    tableData.value = []
    pagination.itemCount = 0
    pagination.pageCount = 0
    return Promise.reject(error)
  } finally {
    emit('onDataChange', tableData.value)
    loading.value = false
  }
}
function handleSearch() {
  pagination.pageNum = 1
  return handleQuery()
}
async function handleReset() {
  const queryItems = { ...props.queryItems }
  for (const key in queryItems) {
    queryItems[key] = ''
  }
  emit('update:queryItems', { ...queryItems, ...initQuery })
  await nextTick()
  pagination.pageNum = 1
  handleQuery()
}
function onPageChange(currentPage: number) {
  pagination.pageNum = currentPage
  handleQuery()
}

defineExpose<CrudTable>({
  tableData,
  pagination,
  loading,
  handleSearch,
  handleReset
})
</script>
